package com.trade.module.database.operation;

import com.trade.common.utils.ResourceLoader;
import com.trade.module.database.basic.ConstConfig;
import lombok.extern.log4j.Log4j;
import org.apache.commons.lang.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 控制数据库查询线程
 * Created by wangchun on 2016/4/12.
 */
@Log4j
public class DBQueryThreadPool {

    private static DBQueryThreadPool dbQueryThreadPool;
    private static Map<String, ThreadPoolExecutor> executorMap = new HashMap<>();
    private static Integer queryThreadNum;

    private DBQueryThreadPool() {
    }

    public static DBQueryThreadPool getInstance() {
        if (dbQueryThreadPool == null) {
            dbQueryThreadPool = new DBQueryThreadPool();
            // 保存任务的队列，无界队列
            queryThreadNum = getQueryThreadNum();
            log.info("查询数据并发线程数：" + queryThreadNum);
        }
        return dbQueryThreadPool;
    }

    /**
     * 从配置文件中获取查询线程数
     *
     * @return
     */
    private static Integer getQueryThreadNum() {
        ResourceLoader resourceLoader = new ResourceLoader(ConstConfig.DDConfigFileName.DB_CONFIG);
        Integer queryThreadNum = 1;
        String queryThreadNumStr = resourceLoader.getPropertiesValue(ConstConfig.DDConfigPropertiesKey.QUERY_THREAD_NUM);
        if (StringUtils.isNotBlank(queryThreadNumStr)) {
            queryThreadNum = Integer.valueOf(queryThreadNumStr);
        }
        return queryThreadNum;
    }

    public void execute(String workId, Runnable runnable) throws Exception {
        ThreadPoolExecutor executor = getThreadPoolExecutor(workId);
        executor.execute(runnable);
    }

    private ThreadPoolExecutor getThreadPoolExecutor(String workId) {
        ThreadPoolExecutor executor = null;
        if (executorMap.containsKey(workId)) {
            executor = executorMap.get(workId);
        } else {
            executor = new ThreadPoolExecutor(queryThreadNum, Integer.MAX_VALUE, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
            executorMap.put(workId, executor);
        }
        return executor;
    }

    public void shutdown(String workId) {
        ThreadPoolExecutor executor = getThreadPoolExecutor(workId);
        if (executor != null) {
            executor.shutdownNow();
            removeThreadPoolExecutor(workId);
        }
    }

    public void removeThreadPoolExecutor(String workId) {
        if (executorMap.containsKey(workId)) {
            executorMap.remove(workId);
        }
    }

}
